home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / abc / examples / wrap.c < prev   
Encoding:
C/C++ Source or Header  |  1994-04-01  |  7.1 KB  |  338 lines  |  [TEXT/R*ch]

  1. /* wrap.c, unwrap.c: wrap and unwrap files with long lines.
  2.    Usage: wrap [-w|-u] [file...]
  3.    Usage: unwrap [-w|-u] [file...]
  4.  
  5.    Wraps the input files by prepending the character START to each line, and
  6.    appending END to the end of the line, or CONT if the following line must
  7.    be appended to it. No wrapped output line is longer than MAXCOL chars.
  8.    If the last line ends with CONT, then there is no '\n' following the
  9.    last line.
  10.    Checksum information is appended for each file.
  11.  
  12.    Unwrap unwraps a file produced by the above command; lines not beginning
  13.    with START are ignored (so mailed wrapped files can be unwrapped, headers
  14.    signatures and all). The checksums are checked for consistency.
  15.  
  16.    Consequently
  17.        wrap file1 file2 | unwrap
  18.    is equivalent to
  19.        cat file1 file2
  20.  
  21.    A filename '-' means standard input.
  22.  
  23.    Flags -w and -u override the program name;
  24.       so "wrap -u" unwraps and "unwrap -w" wraps.
  25.    This is for operating systems that don't support links.
  26.  
  27.    HISTORY:
  28.    LM 910101: original version.
  29.    SP 910215: added -u and -w (for systems with no links)
  30.           added - for stdin
  31.           renamed rindex to standard strrchr
  32.           checked files exist before processing
  33.           handle empty files gracefully when unpacking
  34.           fixed wrap eof bug when input file not newline terminated
  35.           fixed unwrap for multiple files
  36.    SP 910326: rewrite for new format using () (+,
  37.           which protects trailing spaces, and correctly handles files
  38.           that don't end in a newline.
  39.    SP 910905  added -l to give a max line length to wrap (default MAXCOL).
  40. */
  41.  
  42. #include <stdio.h>
  43. extern char *strrchr(), *optarg;
  44.  
  45. #define separator '/'
  46.  
  47. #define MAXCOL 80
  48. #define START '('
  49. #define END ')'
  50. #define CONT '+'
  51. #define CHECK_FRMT "[[wrap saw %d lines, %d chars, %05d hashcode]]\n"
  52. #define CHECK_ME '['
  53.  
  54. #define warning(m, v) {fprintf(stderr, "*** %s, file %s, line %d: ",\
  55.                    progname, filename, lineno);\
  56.             fprintf(stderr, m, v);}
  57.  
  58. int htab[128];
  59.  
  60. init_htab() {
  61.     long r= 1770; int k;
  62.     for (k= 0; k < 128; k++)
  63.         htab[k]= r= (13*r+1)&0x7fff;
  64. }
  65.  
  66. #define hashin(h, c) (((((h)<<4)&0x7fff)^((h)>>11))^htab[((h)^(c))&0x7f])
  67.  
  68. typedef int bool;
  69.  
  70. #define true 1
  71. #define false 0
  72.  
  73. int lineno, lc, cc, hash, maxcol;
  74. char *filename, *progname;
  75.  
  76. errmess(f,a) char *f; {
  77.     fprintf(stderr, f, a);
  78.     exit(1);
  79. }
  80.  
  81. wrap(fp) FILE *fp; {
  82.     int col=1, ch;
  83.     bool any= false;
  84.  
  85.     newchunk();
  86.     while((ch= readchar(fp)) != EOF) {
  87.         any= true;
  88.         if (col == 1) {
  89.             putchar(START);
  90.             col= 2;
  91.         }
  92.         if (ch == '\n') {
  93.             putchar(END);
  94.             col= 0;
  95.         } else if (col == maxcol) {
  96.             putchar(CONT);
  97.             putchar('\n');
  98.             putchar(START);
  99.             col= 2;
  100.         }
  101.         output(ch); col++;
  102.     }
  103.     if (!any) {
  104.         putchar(START);
  105.         col= 2;
  106.     }
  107.     if (col != 1) {
  108.         putchar(CONT);
  109.         putchar('\n');
  110.     }
  111.     printf(CHECK_FRMT, lc, cc, hash);
  112. }
  113.  
  114. bool a_chunk;
  115.  
  116. unwrap(fp) FILE *fp; {
  117.     a_chunk= false;
  118.     while(chunk(fp)) {}
  119.     if (!a_chunk) {
  120.         warning("no line found beginning %c\n", START);
  121.     }
  122. }
  123.  
  124. bool chunk(fp) FILE *fp; {
  125.     newchunk();
  126.     if (skip(fp)) {
  127.         a_chunk= true;
  128.         process(fp);
  129.         check(fp);
  130.         return lookahead(fp) != EOF;
  131.     } else {
  132.         return false;
  133.     }
  134. }
  135.  
  136. bool skip(fp) FILE *fp; {
  137.     while(skipline(fp)) {}
  138.     return lookahead(fp) == START;
  139. }
  140.  
  141. skipline(fp) FILE *fp; {
  142.     int ch= lookahead(fp);
  143.     if (ch == START || ch == EOF) return false;
  144.     ch= readchar(fp);
  145.     while (ch != '\n' && ch != EOF) ch= readchar(fp);
  146.     return true;
  147. }
  148.  
  149. process(fp) FILE *fp; {
  150.     while(copyline(fp)) {}
  151. }
  152.  
  153. copyline(fp) FILE *fp; { /* Copy one line; false = EOF or no more lines */
  154.     int ch= readchar(fp); /* Skip the START */
  155.     if (ch == EOF) return false;
  156.     while(copychar(fp)) {}
  157.     return lookahead(fp) == START;
  158. }
  159.  
  160. copychar(fp) FILE *fp; { /* Copies characters; false = EOL or EOF */
  161.     int ch= readchar(fp);
  162.     int ch1;
  163.     if (ch == EOF) {
  164.         warning("unexpected end of file\n", 0);
  165.         return false;
  166.     }
  167.     while (ch == END || ch == CONT) {
  168.         ch1= readchar(fp);
  169.         if (ch1 == '\n') {
  170.             if (ch == END) output(ch1);
  171.             return false;
  172.         } else if (ch1 == EOF) {
  173.             warning("unexpected end of file\n", 0);
  174.             return false;
  175.         }
  176.         output(ch);
  177.         ch= ch1;
  178.     }
  179.     if (ch == '\n') {
  180.         warning("newline found not preceded by terminator\n", 0);
  181.         output(ch);
  182.         return false;
  183.     }
  184.     output(ch);
  185.     return true;
  186. }
  187.  
  188. int lookahead(fp) FILE *fp; {
  189.     int ch= readchar(fp);
  190.     ungetc(ch, fp);
  191.     return ch;
  192. }
  193.  
  194. check(fp) {
  195.     int wlc, wcc, whc;
  196.  
  197.     if ((fscanf(fp, CHECK_FRMT, &wlc, &wcc, &whc)) != 3) {
  198.         warning("was unable to parse the check line %10s ...\n",
  199.             CHECK_FRMT);
  200.     } else {
  201.         if (wlc != lc || wcc != cc || whc != hash) {
  202.             warning("checking error\n", 0);
  203.             fprintf(stderr, "*** Found        ");
  204.             fprintf(stderr, CHECK_FRMT, wlc, wcc, whc);
  205.             fprintf(stderr, "*** Had expected ");
  206.             fprintf(stderr, CHECK_FRMT, lc, cc, hash);
  207.         }
  208.     }
  209. }
  210.  
  211. newchunk() {
  212.     cc= 0;
  213.     lc= 0;
  214.     hash= 0;
  215.     lineno= 1;
  216. }
  217.  
  218. FILE *do_open(name) char *name; {
  219.     FILE *fp;
  220.     if (strcmp(name, "-") == 0) {
  221.         filename= "standard input";
  222.         return stdin;
  223.     }
  224.     filename= name;
  225.     fp= fopen(name, "r");
  226.     if (fp == NULL) {
  227.         warning("can't open %s\n", name);
  228.     }
  229.     return fp;
  230. }
  231.  
  232. int readchar(fp) FILE *fp; {
  233.     char ch;
  234.  
  235.     ch= getc(fp);
  236.     if (ch == '\n') lineno++;
  237.     return ch;
  238. }
  239.  
  240. output(ch) int ch; {
  241.     cc++;
  242.     if (ch == '\n') {
  243.         lc++;
  244.     }
  245.     hash= hashin(hash, ch);
  246.     putchar(ch);
  247. }
  248.  
  249. bool is_wrap(progname) char *progname; {
  250.     char *p= strrchr(progname, separator);
  251.  
  252.     p= p ? p+1 : progname;
  253.     switch (*p) {
  254.     case 'w':    return 1;
  255.     case 'u':    return 0;
  256.     default:    return 1;
  257.     }
  258. }
  259.  
  260. main(argc, argv) int argc; char *argv[]; {
  261.     int i, err, do_wrap, c, u, w;
  262.     extern int optind;
  263.     FILE *fp;
  264.  
  265.     progname= argv[0];
  266.     filename= "standard input";
  267.  
  268.     if (CHECK_ME != *CHECK_FRMT)
  269.     errmess("*** ERROR 666@#$?!FUBAR -- unauthorised mod to program\n", 0);
  270.  
  271.     if (sizeof(int) < 2) {
  272.         warning("your machine's ints are too short (%d bytes);\n",
  273.                             (int)(sizeof(int)));
  274.         warning("this may cause spurious warnings by unwrap\n", 0);
  275.     }
  276.  
  277.     init_htab();
  278.  
  279.     do_wrap= is_wrap(progname);
  280.  
  281.     /* Process flags */
  282.     err=0; u=0; w=0; maxcol= MAXCOL;
  283.     while ((c= getopt(argc, argv, "uwl:")) != -1) {
  284.         switch (c) {
  285.               case 'u': u=1; do_wrap=0; break;
  286.               case 'w': w=1; do_wrap=1; break;
  287.               case 'l': maxcol= atoi(optarg);
  288.                 if (maxcol<3) {
  289.                     errmess("Line length must be > 2\n", "");
  290.                     exit(1);
  291.                 }
  292.                 break;
  293.               case '?': err=1; break;
  294.         }
  295.     }
  296.  
  297.     if (err || (u == 1 && w == 1)) {
  298.         errmess("Usage: %s [-w|-u|-l length] [file...]\n", argv[0]);
  299.     }
  300.         
  301.     /* Check file arguments */
  302.     err= 0;
  303.     for (i=optind; i<argc; i++) {
  304.         if ((fp= do_open(argv[i])) == NULL) {
  305.             err=1;
  306.         } else fclose(fp);
  307.     }
  308.     if (err) exit(1);
  309.  
  310.     if (do_wrap) {
  311.         printf("This is a wrapped file. ");
  312.         printf("Pipe it through 'unwrap', or edit it by hand:\n");
  313.         printf(" delete all lines that do not begin with %c\n", START);
  314.         printf(" delete the leading %c on all other lines\n", START);
  315.         printf(" delete all trailing %c's\n", END);
  316.         printf(" delete all trailing %c's, and append the following line\n", CONT);
  317.     }
  318.  
  319.     if (argc == optind) { /* No file arguments */
  320.         if (do_wrap) wrap(stdin);
  321.         else unwrap(stdin);
  322.     } else {
  323.         for (i=optind; i<argc; i++) {
  324.             if (strcmp(argv[i], "-") == 0) {
  325.                 if (do_wrap) wrap(stdin);
  326.                 else unwrap(stdin);
  327.             } else if ((fp= do_open(argv[i], "r")) == NULL) {
  328.                 exit(1);
  329.             } else {
  330.                 if (do_wrap) wrap(fp);
  331.                 else unwrap(fp);
  332.                 fclose(fp);
  333.             }
  334.         }
  335.     }
  336.     exit(0);
  337. }
  338.